import json
import logging
from django.contrib.auth import login, logout
from django.contrib.auth.mixins import LoginRequiredMixin
from django.core.paginator import Paginator
from django.shortcuts import render
from django.views import View
from django import http
import re
from django.shortcuts import redirect
from django.urls import reverse
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer

from apps.carts.utils import merge_cart_cookie_to_redis
from apps.goods.models import SKU
# from apps.order.models import OrderInfo, OrderGoods
from meiduo_mall import settings
from utils.response_code import RETCODE
from .models import User
from django.contrib.auth import authenticate
from django_redis import get_redis_connection
from apps.users.utils import check_verify_email_token, generate_verify_email_url

logger = logging.getLogger('django')


# Create your views here.

class RegisterView(View):
    def get(self, request):
        return render(request, 'register.html')

    def post(self, request):
        username = request.POST.get('username')
        password = request.POST.get('password')
        password2 = request.POST.get('password2')
        mobile = request.POST.get('mobile')
        sms_code_client = request.POST.get('sms_code')
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)
        allow = request.POST.get('allow')

        # 判断参数是否齐全
        if not all([username, password, password2, mobile, sms_code_client, allow]):
            return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '缺少参数'})
        # 判断用户名是否是5-20个字符
        if not re.match(r'^[a-zA-Z0-9_]{5,20}$', username):
            return http.JsonResponse({'code': RETCODE.USERERR, 'errmsg': '用户名错误'})
        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
            return http.JsonResponse({'code': RETCODE.PWDERR, 'errmsg': '密码错误'})
        # 判断两次密码是否一致
        if password != password2:
            return http.JsonResponse({'code': RETCODE.CPWDERR, 'errmsg': '确认密码错误'})
        # 判断手机号是否合法
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return http.JsonResponse({'code': RETCODE.MOBILEERR, 'errmsg': '手机号错误'})
        # 判断是否勾选用户协议
        if allow != 'on':
            return http.JsonResponse({'code': RETCODE.ALLOWERR, 'errmsg': '未同意协议'})
        # 判断验证码是否为空
        if sms_code_server is None:
            return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'})
        if sms_code_client != sms_code_server.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'})

        # 保存注册数据
        user = User.objects.create_user(username=username,
                                        password=password,
                                        mobile=mobile)

        login(request, user)
        # 响应注册结果


        return redirect(reverse('contents:index'))
        # return http.HttpResponse('注册成功，重定向到首页')


class UsernameView(View):
    def get(self, request, username):
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'count': count})


class MobileCountView(View):
    def get(self, request, mobile):
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'count': count})


class LoginView(View):
    """用户名登录"""

    def get(self, request):
        return render(request, 'login.html')

    def post(self, request):
        """
        实现登录逻辑
        :param request: 请求对象
        :return: 登录结果
        """
        username = request.POST.get('username')
        password = request.POST.get('pwd')
        remembered = request.POST.get('remembered')
        next = request.GET.get('next')

        if not all([username, password]):
            return http.HttpResponseBadRequest('缺少必要参数')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseBadRequest('请输入正确用户名')

        if not re.match(r'^[a-zA-Z0-9_-]{8,20}$', password):
            return http.HttpResponseBadRequest('请输入正确密码')

        user = authenticate(request, username=username, password=password)
        if user is None:
            return render(request, 'login.html', {'account_errmsg': '用户名或密码错误'})

        login(request, user)

        if remembered != 'on':
            request.session.set_expiry(0)
        else:
            request.session.set_expiry(None)

        # response = redirect(reverse('contents:index'))


        if next:
            response = redirect(next)
        else:
            response = redirect(reverse('contents:index'))

        response.set_cookie('username', user.username, max_age=3600 * 24)
        response = merge_cart_cookie_to_redis(request=request, user=user, response=response)

        return response

        # return redirect(reverse('contents:index'))


class LogoutView(View):
    def get(self, request):
        logout(request)
        response = redirect(reverse('contents:index'))
        response.delete_cookie('username')
        return response


class UserInfoView(LoginRequiredMixin, View):
    login_url = '/login/'

    def get(self, request):
        context = {
            'username': request.user.username,
            'mobile': request.user.mobile,
            'email': request.user.email,
            'email_active': request.user.email_active,
        }

        return render(request, 'user_center_info.html', context=context)


class EmailView(View):
    """添加邮箱"""

    def put(self, request):
        """实现添加邮箱逻辑"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        email = json_dict.get('email')

        # 校验参数
        if not email:
            return http.HttpResponseBadRequest('缺少email参数')
        if not re.match(r'^[a-z0-9][\w\.\-]*@[a-z0-9\-]+(\.[a-z]{2,5}){1,2}$', email):
            return http.HttpResponseBadRequest('参数email有误')

        # 赋值email字段
        try:
            request.user.email = email
            request.user.save()
        except Exception as e:
            logger.error(e)
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '添加邮箱失败'})

        # 异步发送验证邮件
        from celery_tasks.email.tasks import send_verify_email
        # verify_url = '邮件验证链接'
        # send_verify_email.delay(email, verify_url)
        verify_url = generate_verify_email_url(request.user)
        send_verify_email.delay(email, verify_url)

        # 响应添加邮箱结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加邮箱成功'})


class VerifyEmailView(View):
    """验证邮箱"""

    def get(self, request):
        """实现邮箱验证逻辑"""
        # 接收参数
        token = request.GET.get('token')

        # 校验参数：判断token是否为空和过期，提取user
        if not token:
            return http.HttpResponseBadRequest('缺少token')

        user = check_verify_email_token(token)
        if not user:
            return http.HttpResponseBadRequest('无效的token')

        # 修改email_active的值为True
        try:
            user.email_active = True
            user.save()
        except Exception as e:
            logger.error(e)
            return http.HttpResponseServerError('激活邮件失败')

        # 返回邮箱验证结果
        return redirect(reverse('users:userinfo'))



class UserBrowseHistory(LoginRequiredMixin, View):
    """用户浏览记录"""

    def post(self, request):
        """保存用户浏览记录"""
        # 接收参数
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')

        # 校验参数
        try:
            SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseBadRequest('sku不存在')

        # 保存用户浏览数据
        redis_conn = get_redis_connection('history')
        pl = redis_conn.pipeline()
        user_id = request.user.id

        # 先去重
        pl.lrem('history_%s' % user_id, 0, sku_id)
        # 再存储
        pl.lpush('history_%s' % user_id, sku_id)
        # 最后截取
        pl.ltrim('history_%s' % user_id, 0, 4)
        # 执行管道
        pl.execute()

        # 响应结果
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

    def get(self, request):
        """获取用户浏览记录"""
        # 获取Redis存储的sku_id列表信息
        redis_conn = get_redis_connection('history')
        sku_ids = redis_conn.lrange('history_%s' % request.user.id, 0, -1)

        # 根据sku_ids列表数据，查询出商品sku信息
        skus = []
        for sku_id in sku_ids:
            sku = SKU.objects.get(id=sku_id)
            skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'price': sku.price
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'skus': skus})


class UserOrderView(LoginRequiredMixin, View):
    def get(self, request, page_num):
        # 用户登录验证
        user = request.user

        if user is None and user.is_authenticated:
            return http.HttpResponseBadRequest('用户未登录')

        # 展示订单页面 sku,order_id...        # 查询订单
        orders = user.orderinfo_set.all().order_by("-create_time")

        for order in orders:
            order.status_name = OrderInfo.ORDER_STATUS_CHOICES[order.status - 1][1]
            order.pay_method_name = OrderInfo.PAY_METHOD_CHOICES[order.pay_method - 1][1]
            order.sku_list = []

            sku_list = order.skus.all()
            for order_good in sku_list:
                sku = order_good.sku
                sku.count = order_good.count
                sku.amount = sku.count * sku.price
                order.sku_list.append(sku)

        page_num = int(page_num)
        # 分页
        try:
            paginator = Paginator(orders, 2)
            page_orders = paginator.page(page_num)  # 获取当指定页数据
            total_page = paginator.num_pages  # 获取总页数
        except Exception:
            return http.HttpResponseBadRequest('发生错误')

        context = {
            "orders": page_orders,  # 指定页订单所有数据
            'total_page': total_page,
            'page_num': page_num,
        }
        return render(request, "user_center_order.html", context)


class ChangePWDView(View):
    def get(self, request):
        return render(request, 'find_password.html')


class ChangePWDOneView(View):
    def get(self, request, username):
        # 忘记密码图片验证  第一步
        image_code_client = request.GET.get('text')
        uuid = request.GET.get('image_code_id')

        if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
            return http.HttpResponseBadRequest('用户名错误')

        user = User.objects.get(username=username)

        redis_conn = get_redis_connection('code')
        image_code_server = redis_conn.get('img_%s' % uuid)
        if image_code_server is None:
            return http.HttpResponseBadRequest('验证码已过期')

        try:
            redis_conn.delete('img:%s' % uuid)
        except Exception as e:
            logger.error(e)

        image_code_server = image_code_server.decode()
        if image_code_client.lower() != image_code_server.lower():
            return http.HttpResponse('验证码错误')

        serializer = Serializer(settings.SECRET_KEY)
        data = {'user_id': user.id, 'mobile': user.mobile}
        token = serializer.dumps(data).decode()

        return http.JsonResponse({
            'mobile': user.mobile,
            'access_token': token
        })


class ChangePWDTwoView(View):
    def get(self, request, username):
        # 忘记密码 短信验证  第二步
        user = User.objects.get(username=username)
        mobile = user.mobile
        sms_code_client = request.GET.get('sms_code')
        redis_conn = get_redis_connection('code')
        sms_code_server = redis_conn.get('sms_%s' % mobile)

        if sms_code_server is None:
            return render(request, 'register.html', {'sms_code_errmsg': '无效的短信验证码'})
        if sms_code_client != sms_code_server.decode():
            return render(request, 'register.html', {'sms_code_errmsg': '输入短信验证码有误'})

        serializer = Serializer(settings.SECRET_KEY)
        data = {'user_id': user.id, 'mobile': mobile}
        token = serializer.dumps(data).decode()

        return http.JsonResponse({
            'user_id': user.id,
            'access_token': token
        })


class ChangePWDThreeView(View):
    # 修改密码第三步 填写新密码
    def post(self, request, user_id):
        dict = json.loads(request.body.decode())
        pwd = dict.get('password')
        pwd2 = dict.get('password2')
        # access_token = dict.get('access_token')

        # 判断密码是否是8-20个数字
        if not re.match(r'^[0-9A-Za-z]{8,20}$', pwd):
            return http.JsonResponse({'code': RETCODE.PWDERR, 'errmsg': '密码错误'})
        # 判断两次密码是否一致
        if pwd != pwd2:
            return http.JsonResponse({'code': RETCODE.CPWDERR, 'errmsg': '确认密码错误'})

        # serializer = Serializer(settings.SECRET_KEY)

        # try:
        #     data = serializer.loads(access_token)
        # except Exception:
        #     return http.JsonResponse({'code': RETCODE.NECESSARYPARAMERR, 'errmsg': '发生错误'})
        #
        # user_id = data.get('user_id')
        user = User.objects.get(id=user_id)
        try:
            user.set_password(pwd)
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '失败'})

        user.save()

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'ok'})


class OrderCommentView(LoginRequiredMixin, View):
    def get(self, request):

        user = request.user
        order_id = request.GET.get('order_id')

        if user is None and user.is_authenticated:
            return http.HttpResponseBadRequest('用户未登录')
        try:
            order_goods = OrderGoods.objects.filter(order_id=order_id, is_commented=False)
        except Exception:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '订单号错误'})

        uncomment_goods_list = []

        for good in order_goods:
            uncomment_goods_list.append({
                'order_id': order_id,
                'sku_id': good.sku.id,
                'name': good.sku.name,
                'price': str(good.sku.price),
                'default_image_url': good.sku.default_image.url,
                'is_anonymous': str(good.is_anonymous),
                'score': good.score,
                'comment': good.comment

            })

        context = {

            'skus': uncomment_goods_list
        }

        return render(request, 'goods_judge.html', context)

    def post(self, request):
        dict = json.loads(request.body.decode())
        order_id = dict.get('order_id')
        sku_id = dict.get('sku_id')
        score = dict.get('score')
        comment = dict.get('comment')
        is_anonymous = dict.get('is_anonymous')

        if not all([order_id, sku_id, score, comment, is_anonymous]):
            return http.JsonResponse({'code':RETCODE.PARAMERR, 'errmsg':'参数不全'})

        try:
            OrderGoods.objects.filter(order_id=order_id, is_anonymous=False)
        except Exception:
            return http.JsonResponse({'code':RETCODE.PARAMERR, 'errmsg':'订单错误'})

        try:
            sku = SKU.objects.get(id=sku_id)
        except Exception:
            return http.JsonResponse({'code':RETCODE.PARAMERR, 'errmsg':'参数错误'})

        OrderGoods.objects.filter(order_id=order_id, sku_id=sku_id, is_commented=False).update(
            comment=comment,
            score=score,
            is_anonymous=is_anonymous,
            is_commented=True
        )

        sku.comments += 1
        sku.save()
        sku.spu.comments += 1
        sku.spu.save()

        if OrderGoods.objects.filter(order_id=order_id, is_commented=False).count() == 0:
            OrderInfo.objects.filter(order_id=order_id).update(status=OrderInfo.ORDER_STATUS_ENUM['FINISHED'])

        return http.JsonResponse({'code':RETCODE.OK, 'errmsg':'ok'})




